package com.macro.mall.portal.service.impl;

import com.alibaba.fastjson.JSONObject;
import com.macro.mall.common.api.CommonResult;
import com.macro.mall.mapper.OmsOrderMapper;
import com.macro.mall.mapper.PayLogMapper;
import com.macro.mall.model.OmsOrder;
import com.macro.mall.model.OmsOrderExample;
import com.macro.mall.model.PayLog;
import com.macro.mall.model.PayLogExample;
import com.macro.mall.portal.config.WxPayConfig;
import com.macro.mall.portal.request.CreateOrderReq;
import com.macro.mall.portal.request.QueryOrderReq;
import com.macro.mall.portal.service.OmsPortalOrderService;
import com.macro.mall.portal.service.WxPayService;
import com.macro.mall.portal.util.HttpServletUtils;
import com.macro.mall.portal.util.MemberUtils;
import com.wechat.pay.java.core.RSAAutoCertificateConfig;
import com.wechat.pay.java.core.exception.HttpException;
import com.wechat.pay.java.core.exception.MalformedMessageException;
import com.wechat.pay.java.core.exception.ServiceException;
import com.wechat.pay.java.core.notification.NotificationParser;
import com.wechat.pay.java.core.notification.RequestParam;
import com.wechat.pay.java.service.payments.jsapi.JsapiServiceExtension;
import com.wechat.pay.java.service.payments.jsapi.model.*;
import com.wechat.pay.java.service.payments.model.Transaction;
import com.wechat.pay.java.service.refund.RefundService;
import com.wechat.pay.java.service.refund.model.AmountReq;
import com.wechat.pay.java.service.refund.model.CreateRequest;
import com.wechat.pay.java.service.refund.model.Refund;
import com.wechat.pay.java.service.refund.model.Status;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import javax.annotation.Resource;
import javax.servlet.http.HttpServletRequest;
import java.util.*;

/**
 * @ClassName WxPayService
 * @Package com.macro.mall.portal.service
 * @Description TODO
 * @Author wsx
 * @Date 2024/8/719:18
 * @Version V1.0
 * @Copyright yunshan
 */
@Slf4j
@Service
public class WxPayServiceImpl implements WxPayService {

    @Resource
    private WxPayConfig wxPayConfig;

    @Resource
    private RSAAutoCertificateConfig rsaAutoCertificateConfig;

    @Autowired
    private OmsOrderMapper orderMapper;

    @Autowired
    private OmsPortalOrderService portalOrderService;

    @Autowired
    private StringRedisTemplate stringRedisTemplate;

    @Autowired
    private PayLogMapper payLogMapper;

    /***
     * 预支付订单
     * @return
     */
    @Override
    public CommonResult<Object> createOrder(CreateOrderReq req) throws Exception {
        if (req == null) {
            return CommonResult.failed("创建订单失败，缺少参数！");
        }
        //先解密
        String orderNo = req.getOutTradeNo();
        Integer totalFee = req.getTotal();
        String description = req.getDescription();
        String openId =  MemberUtils.getUser().getOpenId();
        
        totalFee = 1;

        //创建初始化订单
        //请求微信支付相关配置 不填默认为RSA
        JsapiServiceExtension service =
                new JsapiServiceExtension.Builder()
                        .config(rsaAutoCertificateConfig).signType("RSA").build();
        PrepayWithRequestPaymentResponse response = new PrepayWithRequestPaymentResponse();
        try {
            PrepayRequest request = new PrepayRequest();
            request.setAppid(wxPayConfig.getPayAppId());
            request.setMchid(wxPayConfig.getMerchantId());
            request.setDescription(description);
            request.setOutTradeNo(orderNo);
            request.setNotifyUrl(wxPayConfig.getPayNotifyUrl());
            Amount amount = new Amount();
            //amount.setTotal(totalFee.multiply(new BigDecimal("100")).intValue());
            amount.setTotal(totalFee);
            request.setAmount(amount);
            Payer payer = new Payer();
            payer.setOpenid(openId);
            request.setPayer(payer);
            log.info("请求预支付下单，请求参数：{}", JSONObject.toJSONString(request));
            // 调用预下单接口
            response = service.prepayWithRequestPayment(request);
            log.info("订单【{}】发起预支付成功，返回信息：{}", orderNo, response);
            PayLog pl=new PayLog();
            pl.setOutTradeNo(orderNo);
            pl.setCreateTime(new Date());
            pl.setPayInitReq(JSONObject.toJSONString(request));
            pl.setPayInitRsp(JSONObject.toJSONString(response));
            pl.setUserId(MemberUtils.getUser().getId());
            payLogMapper.insertSelective(pl);
        } catch (HttpException e) { // 发送HTTP请求失败
            log.error("微信下单发送HTTP请求失败，错误信息：{}", e.getHttpRequest());
            return CommonResult.failed("下单失败");
        } catch (ServiceException e) { // 服务返回状态小于200或大于等于300，例如500
            log.error("微信下单服务状态错误，错误信息：{}", e.getErrorMessage());
            return CommonResult.failed("下单失败");
        } catch (MalformedMessageException e) { // 服务返回成功，返回体类型不合法，或者解析返回体失败
            log.error("服务返回成功，返回体类型不合法，或者解析返回体失败，错误信息：{}", e.getMessage());
            return CommonResult.failed("下单失败");
        }
        return CommonResult.success(response);
    }


    /***
     * 微信支付回调通知
     * @param request
     * @return
     */
    @Transactional
    @Override
    public synchronized String payNotify(HttpServletRequest request) throws Exception {
        log.info("------收到支付通知------");
        // 请求头Wechatpay-Signature
        String signature = request.getHeader("Wechatpay-Signature");
        // 请求头Wechatpay-nonce
        String nonce = request.getHeader("Wechatpay-Nonce");
        // 请求头Wechatpay-Timestamp
        String timestamp = request.getHeader("Wechatpay-Timestamp");
        // 微信支付证书序列号
        String serial = request.getHeader("Wechatpay-Serial");
        // 签名方式
        String signType = request.getHeader("Wechatpay-Signature-Type");
        // 构造 RequestParam
        RequestParam requestParam = new RequestParam.Builder()
                .serialNumber(serial)
                .nonce(nonce)
                .signature(signature)
                .timestamp(timestamp)
                .signType(signType)
                .body(HttpServletUtils.getRequestBody(request))
                .build();

        // 初始化 NotificationParser
        NotificationParser parser = new NotificationParser(rsaAutoCertificateConfig);
        // 以支付通知回调为例，验签、解密并转换成 Transaction
        log.info("验签参数：{}", requestParam);
        Transaction transaction = parser.parse(requestParam, Transaction.class);
        log.info("验签成功！-支付回调结果：{}", transaction.toString());

        Map<String, String> returnMap = new HashMap<>(2);
        returnMap.put("code", "FAIL");
        returnMap.put("message", "失败");
        //获取订单号查询订单
        String outTradeNo = transaction.getOutTradeNo();
        OmsOrderExample orderExample = new OmsOrderExample();
        orderExample.createCriteria()
                .andOrderSnEqualTo(outTradeNo)
                .andDeleteStatusEqualTo(0)
                .andStatusNotEqualTo(0);
        List<OmsOrder> omsOrders = orderMapper.selectByExample(orderExample);
        if(omsOrders != null && !omsOrders.isEmpty()){
            OmsOrder omsOrder = omsOrders.get(0);
            //判断订单是否已经不是待付款状态，如果不是证明已经进行过处理，直接返回
            if (omsOrder != null) {
                returnMap.put("code", "SUCCESS");
                returnMap.put("message", "成功");
                return JSONObject.toJSONString(returnMap);
            }
        }
        //记录日志
        PayLogExample ple= new PayLogExample();
        ple.createCriteria().andOutTradeNoEqualTo(outTradeNo);
        List<PayLog> payLogs = payLogMapper.selectByExample(ple);
        if(payLogs !=null && !payLogs.isEmpty()){
            PayLog payLog = payLogs.get(0);
            payLog.setTransactionId(transaction.getTransactionId());
            payLog.setRemark(nonce);
            payLog.setPayReturnInfo(JSONObject.toJSONString(transaction));
            payLogMapper.updateByPrimaryKeySelective(payLog);
        }
        if (Transaction.TradeStateEnum.SUCCESS != transaction.getTradeState()) {
            log.info("内部订单号【{}】,微信支付订单号【{}】支付未成功", transaction.getOutTradeNo(), transaction.getTransactionId());
            return JSONObject.toJSONString(returnMap);
        }
        portalOrderService.paySuccessByOrderSn(transaction.getOutTradeNo(),2);
        returnMap.put("code", "SUCCESS");
        returnMap.put("message", "成功");
        return JSONObject.toJSONString(returnMap);
    }

    /***
     * 根据商户订单号查询订单 outTradeNo
     * @param req
     * @return
     */
    @Transactional
    @Override
    public CommonResult<Object> queryOrderByOrderNo(QueryOrderReq req) {
        QueryOrderByOutTradeNoRequest queryRequest = new QueryOrderByOutTradeNoRequest();
        queryRequest.setMchid(wxPayConfig.getMerchantId());
        queryRequest.setOutTradeNo(req.getOrderNo());
        try {
            JsapiServiceExtension service =
                    new JsapiServiceExtension.Builder()
                            .config(rsaAutoCertificateConfig)
                            .signType("RSA")
                            .build();
            Transaction result = service.queryOrderByOutTradeNo(queryRequest);
            LinkedHashMap retmap = new LinkedHashMap();
            //支付成功
            if (Transaction.TradeStateEnum.SUCCESS == result.getTradeState()) {
                log.info("内部订单号【{}】,微信支付订单号【{}】支付成功", result.getOutTradeNo(), result.getTransactionId());
                retmap.put("out_trade_no", result.getOutTradeNo());
                retmap.put("transaction_id", result.getTransactionId());
                retmap.put("success", true);
                retmap.put("msg", "支付成功！");
                String successTime = result.getSuccessTime();
                retmap.put("success_time", successTime);
                //主动查询
                OmsOrderExample orderExample = new OmsOrderExample();
                orderExample.createCriteria()
                        .andOrderSnEqualTo(result.getOutTradeNo())
                        .andDeleteStatusEqualTo(0)
                        .andStatusNotEqualTo(0);
                List<OmsOrder> omsOrders = orderMapper.selectByExample(orderExample);
                if(omsOrders != null && !omsOrders.isEmpty()){
                    OmsOrder omsOrder = omsOrders.get(0);
                    //判断订单是否已经不是待付款状态，如果不是证明已经进行过处理，直接返回
                    if (omsOrder != null) {
                        return CommonResult.success(retmap);
                    }
                }
                portalOrderService.paySuccessByOrderSn(result.getOutTradeNo(),2);
            } else {
                log.info("内部订单号【{}】,微信支付订单号【{}】支付未成功", result.getOutTradeNo(), result.getTransactionId());
                retmap.put("out_trade_no", result.getOutTradeNo());
                retmap.put("transaction_id", result.getTransactionId());
                retmap.put("success", false);
                retmap.put("msg", "支付失败！");
                retmap.put("success_time", null);
            }
            return CommonResult.success(retmap);
        } catch (ServiceException e) {
            log.error("订单查询失败，返回码：{},返回信息：{}", e.getErrorCode(), e.getErrorMessage());
            return CommonResult.failed("订单查询失败！");
        }
    }

    /***
     * 根据支付订单号查询订单 paymentNo
     * @param req
     * @return
     */
    @Transactional
    @Override
    public Object queryOrderByPaymentNo(QueryOrderReq req) {
        QueryOrderByIdRequest queryRequest = new QueryOrderByIdRequest();
        queryRequest.setMchid(wxPayConfig.getMerchantId());
        queryRequest.setTransactionId(req.getPaymentNo());
        try {
            JsapiServiceExtension service =
                    new JsapiServiceExtension.Builder()
                            .config(rsaAutoCertificateConfig)
                            .signType("RSA") // 不填默认为RSA
                            .build();
            Transaction result = service.queryOrderById(queryRequest);
            LinkedHashMap map = new LinkedHashMap();
            //支付成功
            if (Transaction.TradeStateEnum.SUCCESS == result.getTradeState()) {
                log.info("内部订单号【{}】,微信支付订单号【{}】支付成功", result.getOutTradeNo(), result.getTransactionId());
                map.put("out_trade_no", result.getOutTradeNo());
                map.put("transaction_id", result.getTransactionId());
                map.put("success", true);
                map.put("msg", "支付成功！");
                map.put("success_time", result.getSuccessTime());
                //主动查询
//                Wrapper wrapper = new EntityWrapper<WxOrderEntity>();
//                wrapper.eq("transaction_id", req.getPaymentNo());
//                WxOrderEntity wxOrderEntity = wxOrderDataService.selectOne(wrapper);
//                if (wxOrderEntity != null) {
//                    if (wxOrderEntity.getPayStatus() != 1) {
//                        wxOrderEntity.setPayStatus(1);
//                        wxOrderEntity.setPayDate(DateUtils.stringToDateTime(result.getSuccessTime()));
//                        wxOrderEntity.setPayTime(DateUtils.stringToDateTime(result.getSuccessTime()));
//                        wxOrderEntity.setUpdateTime(new Date());
//                        wxOrderDataService.updateById(wxOrderEntity);
//                        //同时处理支付记录
//                        Wrapper payWrapper = new EntityWrapper<WxPayLogEntity>();
//                        wrapper.eq("transaction_id", req.getPaymentNo());
//                        WxPayLogEntity wxPayLogEntity = wxPayLogDataService.selectOne(payWrapper);
//                        if (wxPayLogEntity == null) {
//                            wxPayLogEntity = new WxPayLogEntity();
//                            wxPayLogEntity.setCreateTime(new Date());
//                            wxPayLogEntity.setOutTradeNo(wxOrderEntity.getOutTradeNo());
//                            wxPayLogEntity.setPayStatus(1);
//                            wxPayLogEntity.setTotalFee(wxOrderEntity.getTotalFee());
//                            wxPayLogEntity.setTransactionId(result.getTransactionId());
//                            wxPayLogEntity.setWxOpenId(wxOrderEntity.getWxOpenId());
//                            wxPayLogDataService.insert(wxPayLogEntity);
//                        }
//                    }
//                }
            } else {
                log.info("内部订单号【{}】,微信支付订单号【{}】支付未成功", result.getOutTradeNo(), result.getTransactionId());
                map.put("out_trade_no", result.getOutTradeNo());
                map.put("transaction_id", result.getTransactionId());
                map.put("success", false);
                map.put("msg", "支付失败！");
                map.put("success_time", null);
            }
            return CommonResult.success(map);
        } catch (ServiceException e) {
            log.error("订单查询失败，返回码：{},返回信息：{}", e.getErrorCode(), e.getErrorMessage());
            return CommonResult.failed("订单查询失败！");
        }
    }

    /***
     * 微信申请退款
     * @param outTradeNo 商户订单号
     * @param totalAmount
     * @return
     */
    @Override
    public Object createRefund(String outTradeNo, Long totalAmount) {
        //返回参数
        LinkedHashMap map = new LinkedHashMap();
        map.put("out_trade_no", outTradeNo);
        map.put("success", false);
        map.put("msg", "正在申请退款中！");
        String outRefundNo = "REFUND_" + outTradeNo;
        map.put("out_refund_no", outRefundNo);
        //申请退款订单，需要变更订单记录
//        Wrapper wrapper = new EntityWrapper<WxOrderEntity>();
//        wrapper.eq("out_trade_no", outTradeNo);
//        WxOrderEntity wxOrderEntity = wxOrderDataService.selectOne(wrapper);
//        if (wxOrderEntity == null) {
//            return R.error("订单不存在，申请退款不存在！");
//        }
//        wxOrderEntity.setPayStatus(4);//退款中
//        wxOrderEntity.setUpdateTime(new Date());
//        wxOrderDataService.updateById(wxOrderEntity);
        try {
            // 构建退款service
            RefundService service = new RefundService.Builder()
                    .config(rsaAutoCertificateConfig)
                    .build();
            CreateRequest request = new CreateRequest();
            // 调用request.setXxx(val)设置所需参数，具体参数可见Request定义
            request.setOutTradeNo(outTradeNo);
            request.setOutRefundNo(outRefundNo);

            AmountReq amount = new AmountReq();
            amount.setTotal(totalAmount);
            amount.setRefund(totalAmount);
            amount.setCurrency("CNY");

            request.setAmount(amount);
            request.setNotifyUrl(wxPayConfig.getRefundNotifyUrl());

            //接收退款返回参数
            Refund refund = service.create(request);
            log.info("退款返回信息：{}", refund);
            if (refund.getStatus().equals(Status.SUCCESS)) {
                map.put("success", true);
                map.put("msg", "退款成功！");
                //说明退款成功，开始接下来的业务操作
                //主动查询
//                Wrapper againWrapper = new EntityWrapper<WxOrderEntity>();
//                againWrapper.eq("out_trade_no", outTradeNo);
//                WxOrderEntity orderEntity = wxOrderDataService.selectOne(againWrapper);
//                if (orderEntity != null) {
//                    orderEntity.setPayStatus(3);//退款成功
//                    orderEntity.setUpdateTime(new Date());
//                    wxOrderDataService.updateById(orderEntity);
//                    //同时处理退款记录
//                    Wrapper payWrapper = new EntityWrapper<WxPayLogEntity>();
//                    payWrapper.eq("out_trade_no", outTradeNo);
//                    payWrapper.eq("pay_status", 2);//退款
//                    WxPayLogEntity wxPayLogEntity = wxPayLogDataService.selectOne(payWrapper);
//                    if (wxPayLogEntity == null) {
//                        wxPayLogEntity = new WxPayLogEntity();
//                        wxPayLogEntity.setCreateTime(new Date());
//                        wxPayLogEntity.setOutTradeNo(outTradeNo);
//                        wxPayLogEntity.setPayStatus(2);
//                        wxPayLogEntity.setTotalFee(totalAmount.intValue());
//                        wxPayLogEntity.setTransactionId(wxOrderEntity.getTransactionId());
//                        wxPayLogEntity.setOutRefundNo(outRefundNo);
//                        wxPayLogEntity.setWxOpenId(wxOrderEntity.getWxOpenId());
//                        wxPayLogDataService.insert(wxPayLogEntity);
//                    }
//                }
            }
        } catch (ServiceException e) {
            log.error("退款失败！，错误信息：{}", e.getMessage());
            return CommonResult.failed("退款失败！");
        } catch (Exception e) {
            log.error("服务返回成功，返回体类型不合法，或者解析返回体失败，错误信息：{}", e.getMessage());
            return CommonResult.failed("退款失败！");
        }
        return CommonResult.success(map);
    }
}
